package commons.utils.primitive_geom;

import commons.utils.Utils.Side;


// Attention à tous les constructeurs prenant des Point_d ou autre Vector_d
// Si le but de ces Vector_d est de faire des calculs, il ne faudrait pas alors modifier les arguements des constructeurs ...
// Dans ce cas, utiliser Vector_d.createCopyFrom(...)
public class Vector_d extends Segment_d {


	public Vector_d(double x1, double y1, double x2, double y2) {
		super(x1, y1, x2, y2);
	}

	public Vector_d(Point_d pt1, Point_d pt2) {
		super (pt1, pt2);
	}

	public Vector_d(Segment_d seg) {
		super(seg);
	}

	public Vector_d() {
		super();
	}

	public static Vector_d createCopyFrom(Vector_d vToCopy) {
		Vector_d v = new Vector_d();
		v.takeCoordFrom(vToCopy);
		return v;
	}
	public static Vector_d createCopyFrom(Point_d pt1ToCopy, Point_d pt2ToCopy) {
		Vector_d v = new Vector_d();
		v.takeCoordFrom(pt1ToCopy, pt2ToCopy);
		return v;
	}

	// Attention : modifie this en plus de le renvoyer !!
	public Vector_d normalize() {
		double lg = getLength();
		if (lg>0)
			multiplyBy(1/lg);
		return this;
	}

	// Attention : modifie this en plus de le renvoyer !!
	public Vector_d multiplyBy(double factor) {
		pt2.x = pt1.x + (pt2.x-pt1.x)*factor;
		pt2.y = pt1.y + (pt2.y-pt1.y)*factor;
		return this;
	}

	// Attention : modifie this en plus de le renvoyer !!
	public Vector_d add (Vector_d vToAdd) {
		this.pt2.x += (vToAdd.pt2.x - vToAdd.pt1.x);
		this.pt2.y += (vToAdd.pt2.y - vToAdd.pt1.y);
		return this;
	}

	//translate le vecteur pour qu'il garde le meme module, la meme direction, mais un point de départ fourni
	public void setPointDepart(Point_d fromPt) {
		double dx = fromPt.x - this.pt1.x;
		double dy = fromPt.y - this.pt1.y;
		translate (dx, dy);
	}


	// La base du vbecteur unitaire renvoyer est le Pt1 de this
	public Vector_d getVectUnitaire() {
		double l = getLength();
		if (l==0) return null;

		Vector_d vUnit = Vector_d.createCopyFrom(this);
		vUnit.multiplyBy(1/l);
		return vUnit;
	}


	public Vector_d getVectUnitaireNormalDroite() {
		Vector_d vect = getVectUnitaire();
		if (vect==null) return null;

		double pt2x_temp = vect.pt2.x;
		vect.pt2.x = vect.pt1.x + (vect.pt2.y - vect.pt1.y);
		vect.pt2.y = vect.pt1.y - (pt2x_temp - vect.pt1.x);

		return vect;
	}


	public Vector_d getVectUnitaireNormalGauche() {
		Vector_d vect = getVectUnitaire();
		if (vect==null) return null;

		double pt2x_temp = vect.pt2.x;
		vect.pt2.x = vect.pt1.x - (vect.pt2.y - vect.pt1.y);
		vect.pt2.y = vect.pt1.y + (pt2x_temp - vect.pt1.x);
		return vect;
	}


	//renvoie null si le pt est dans l'axe de this
	public Side getSideForPoint(Point_d pt) {
		return getSideForPoint(this, pt);
	}
	
	static public Side getSideForPoint(Segment_d seg, Point_d pt) {
		double ux, uy, vx, vy;
		ux = seg.pt2.x - seg.pt1.x;
		uy = seg.pt2.y - seg.pt1.y;
		vx = pt.x - seg.pt1.x;
		vy = pt.y - seg.pt1.y;

		double z = ux*vy-uy*vx;
		if (z > 0)
			return Side.LEFT;
		else if (z < 0)
			return Side.RIGHT;
		else
			return null;
	}

	public double cosinusWith (Vector_d v) {
		double produitLongueur = this.getLength() * v.getLength();
		if (produitLongueur==0)
			return 1;
		double cos = ((this.pt2.x-this.pt1.x) * (v.pt2.x-v.pt1.x) + (this.pt2.y-this.pt1.y) * (v.pt2.y-v.pt1.y)) / (produitLongueur);
//		if (cos<-1 || cos>1)
//			cos = cos+1-1;
		assert (cos>=-1.00001 && cos <=1.00001) : cos;
		return cos;
	}

}
